package com.xjrsoft.common.advice;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.xjrsoft.common.annotation.Trans;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.TransType;
import com.xjrsoft.common.model.result.R;
import com.xjrsoft.common.page.PageOutput;
import com.xjrsoft.common.utils.RedisUtil;
import com.xjrsoft.module.magicapi.service.IMagicApiService;
import com.xjrsoft.module.organization.entity.Department;
import com.xjrsoft.module.organization.entity.Post;
import com.xjrsoft.module.organization.entity.User;
import com.xjrsoft.module.system.entity.Area;
import com.xjrsoft.module.system.entity.DictionaryDetail;
import com.xjrsoft.module.system.entity.Tree;
import com.xjrsoft.module.system.service.IAreaService;
import com.xjrsoft.module.system.service.ITreeService;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import org.ssssssss.magicapi.modules.db.model.PageResult;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 接口返回值转换
 * 例如： 列表中的 数据字典 用户 机构 岗位等值  使用id 转 name
 * @Author: tzx
 * @Date: 2023/1/11 14:42
 */
@Slf4j
@RestControllerAdvice
@AllArgsConstructor
public class TransResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    private RedisUtil redisUtil;

    private final IMagicApiService magicApiService;

    private final IAreaService areaService;

    private final ITreeService treeService;

    @Override
    public boolean supports(@NonNull MethodParameter returnType, @NonNull Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, @NonNull MethodParameter returnType, @NonNull MediaType selectedContentType, @NonNull Class selectedConverterType, @NonNull ServerHttpRequest request, @NonNull ServerHttpResponse response) {

        if (!(body instanceof R)) {
            return body;
        }

        if (((R)body).getData() == null) {
            return body;
        }

        //判断是否为分页返回值
        if (ClassUtil.equals(((R) body).getData().getClass(), PageOutput.class.getName(), true)) {
            Object result = Convert.convert(R.class, body).getData();
            PageOutput<?> pageOutput = Convert.convert(PageOutput.class, result);
            List<?> listData = pageOutput.getList();
            if (listData == null || listData.size() == 0) {
                return body;
            }
            //默认取第一条数据 来获取是所有字段  以及 字段的 注解
            Object firstData = listData.get(0);
            Field[] fields = ReflectUtil.getFields(firstData.getClass());
            //获取到所有字段的转换注解
            List<Trans> transList = Arrays.stream(fields).filter(field -> field.isAnnotationPresent(Trans.class)).map(field -> field.getAnnotation(Trans.class)).collect(Collectors.toList());

            //如果一个需要转换的都没  直接返回
            if (transList.size() == 0) {
                return body;
            }

            transData(listData, fields, transList);

        }

        //判断是否为不分页列表返回值
        else if (ClassUtil.equals(((R) body).getData().getClass(), ArrayList.class.getName(), true)){
            Object result = Convert.convert(R.class, body).getData();
            List<?> listData = Convert.convert(List.class, result);
            if (listData == null || listData.size() == 0) {
                return body;
            }
            //默认取第一条数据 来获取是所有字段  以及 字段的 注解
            Object firstData = listData.get(0);
            Field[] fields = ReflectUtil.getFields(firstData.getClass());
            //获取到所有字段的转换注解
            List<Trans> transList = Arrays.stream(fields).filter(field -> field.isAnnotationPresent(Trans.class)).map(field -> field.getAnnotation(Trans.class)).collect(Collectors.toList());

            //如果一个需要转换的都没  直接返回
            if (transList.size() == 0) {
                return body;
            }
            transData(listData, fields, transList);
        }
        //单个的返回值 （表单页面不需要 详情页面可以使用）
        else {
            Object result = Convert.convert(R.class, body).getData();

            Field[] fields = ReflectUtil.getFields(result.getClass());
            //获取到所有字段的转换注解
            List<Trans> transList = Arrays.stream(fields).filter(field -> field.isAnnotationPresent(Trans.class)).map(field -> field.getAnnotation(Trans.class)).collect(Collectors.toList());

            //如果一个需要转换的都没  直接返回
            if (transList.size() == 0) {
                return body;
            }
            List<Object> listData = new ArrayList<>();
            listData.add(result);
            transData(listData, fields, transList);
        }
        return body;
    }

    private void transData(List<?> listData, Field[] fields, List<Trans> transList) {
        List<DictionaryDetail> detailList = getDictionaryDetails(transList);
        List<User> userList = getUsers(transList);
        List<Department> deptList = getDepts(transList);
        List<Post> postList = getPosts(transList);
//        List<Area> areaList = getAreas(transList);
        Map<String, List<Map<String, Object>>> apiDataList = getApiData(transList);
        Map<String, List<Map<String, Object>>> treeDataList = getTreeData(transList);

        for (Object data : listData) {
            for (Field field : fields) {
                Trans annotation = field.getAnnotation(Trans.class);
                if (annotation == null) {
                    continue;
                }
                try {
                    field.setAccessible(true);
                    Object value = field.get(data);
                    if (StrUtil.isEmptyIfStr(value)) {
                        continue;
                    }
                    List<String> values = annotation.isMulti() ? StrUtil.split(value.toString(), StringPool.COMMA) : Arrays.asList(value.toString());
                    StringBuilder tranValue = new StringBuilder();
                    //数据字典转换
                    if (annotation.type() == TransType.DIC && detailList != null) {
                        for (DictionaryDetail detail : detailList) {
                            if (values.contains(detail.getValue()) && StrUtil.equalsIgnoreCase(annotation.id(), detail.getItemId().toString())) {
                                if (tranValue.length() > 0) {
                                    tranValue.append(StringPool.COMMA);
                                }
                                tranValue.append(detail.getName());
                                if (values.size() == 1) break;
                            }
                        }
                    }
                    // api数据转换
                    if (annotation.type() == TransType.API && CollectionUtils.isNotEmpty(apiDataList)) {
                        List<Map<String, Object>> dataList = apiDataList.get(annotation.id());
                        for (Map<String, Object> item : dataList) {
                            if (values.contains(MapUtils.getString(item, "value"))) {
                                if (tranValue.length() > 0) {
                                    tranValue.append(StringPool.COMMA);
                                }
                                tranValue.append(MapUtils.getString(item, "label"));
                                if (values.size() == 1) break;
                            }
                        }
                    }
                    //用户转换
                    if (annotation.type() == TransType.USER && userList != null) {
                        values = StrUtil.split(value.toString(), StringPool.COMMA);
                        for (User user : userList) {
                            if (values.contains(user.getId().toString())) {
                                if (tranValue.length() > 0) {
                                    tranValue.append(StringPool.COMMA);
                                }
                                tranValue.append(user.getName());
                                if (values.size() == 1) break;
                            }
                        }
                    }
                    //部门转换
                    if (annotation.type() == TransType.DEPT && deptList != null) {
                        for (Department department : deptList) {
                            if (StrUtil.equals(department.getId().toString(), value.toString())) {
                                tranValue.append(department.getName());
                                break;
                            }
                        }
                    }
                    //岗位转换
                    if (annotation.type() == TransType.POST && postList != null) {
                        for (Post post : postList) {
                            if (StrUtil.equals(value.toString(), post.getId().toString())) {
                                tranValue.append(post.getName());
                                break;
                            }
                        }
                    }
                    //行政区域
                    if (annotation.type() == TransType.AREA) {
                        values = StrUtil.split(value.toString(), StringPool.COMMA);
                        for (String id : values) {
                            Area area = areaService.getById(Long.valueOf(id));
                            if (tranValue.length() > 0) {
                                tranValue.append(StringPool.SLASH);
                            }
                            tranValue.append(area.getName());
                        }
                    }
                    //级联
                    if (annotation.type() == TransType.CASCADE && CollectionUtils.isNotEmpty(apiDataList)) {
                        values = StrUtil.split(value.toString(), StringPool.COMMA);
                        List<Map<String, Object>> tempList = apiDataList.get(annotation.id());
                        boolean isShowAll = StrUtil.equalsIgnoreCase(annotation.showFormat(), "all");
                        for (String savedValue : values) {
                            for (Map<String, Object> item : tempList) {
                                if (StrUtil.equals(savedValue, MapUtils.getString(item, "value"))) {
                                    if (!isShowAll) {
                                        tranValue.setLength(0);
                                    }
                                    if (tranValue.length() > 0) tranValue.append(annotation.separator());
                                    tranValue.append(MapUtils.getString(item, "label"));
                                    tempList = (List<Map<String, Object>>) item.get("children");
                                }
                            }
                        }
                    }
                    if (annotation.type() == TransType.TREE && CollectionUtils.isNotEmpty(treeDataList)) {
                        List<Map<String, Object>> dataList = treeDataList.get(annotation.id());
                        for (Map<String, Object> item : dataList) {
                            if (values.contains(MapUtils.getString(item, "value"))) {
                                if (tranValue.length() > 0) {
                                    tranValue.append(StringPool.COMMA);
                                }
                                tranValue.append(MapUtils.getString(item, "label"));
                                if (values.size() == 1) break;
                            }
                        }
                    }
                    if (tranValue.length() > 0) field.set(data, tranValue.toString());
                } catch (Exception e) {
                    log.warn(field.getName() + annotation.type().getValue() + "数据转换异常！");
                }
            }
        }
    }

    private List<DictionaryDetail> getDictionaryDetails(List<Trans> transList) {

        List<DictionaryDetail> detailList = new ArrayList<>();
        //如果有需要转换的数据字典
        if (transList.stream().anyMatch(t -> t.type() == TransType.DIC)) {
            detailList = redisUtil.get(GlobalConstant.DIC_DETAIL_CACHE_KEY, new TypeReference<List<DictionaryDetail>>() {
            });
        }
        return detailList;
    }

    private List<User> getUsers(List<Trans> transList) {
        List<User> userList = new ArrayList<>();
        //如果有需要转换的用户
        if(transList.stream().anyMatch(t -> t.type() == TransType.USER)){
            userList= redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
            });
        }
        return userList;
    }

    private List<Department> getDepts(List<Trans> transList) {

        List<Department> detailList = new ArrayList<>();
        //如果有需要转换的部门
        if (transList.stream().anyMatch(t -> t.type() == TransType.DEPT)) {
            detailList = redisUtil.get(GlobalConstant.DEP_CACHE_KEY, new TypeReference<List<Department>>() {
            });
        }
        return detailList;
    }

    private List<Post> getPosts(List<Trans> transList) {
        List<Post> userList = new ArrayList<>();
        //如果有需要转换的用户
        if(transList.stream().anyMatch(t -> t.type() == TransType.POST)){
            userList= redisUtil.get(GlobalConstant.POST_CACHE_KEY, new TypeReference<List<Post>>() {
            });
        }
        return userList;
    }

    private Map<String, List<Map<String, Object>>> getApiData(List<Trans> transList) {
        Map<String, List<Map<String, Object>>> resultMap = new HashMap<>();
        for (Trans trans : transList) {
            if (trans.type() == TransType.API || trans.type() == TransType.CASCADE) {
                Object apiDataList = magicApiService.executeApi(trans.id());
                if (apiDataList instanceof PageResult) {
                    resultMap.put(trans.id(), (List<Map<String, Object>>) ((PageResult) apiDataList).getList());
                } else if (apiDataList instanceof List) {
                    resultMap.put(trans.id(), (List<Map<String, Object>>) apiDataList);
                }
            }
        }
        return resultMap;
    }

    private Map<String, List<Map<String, Object>>> getTreeData(List<Trans> treeList) {
        Map<String, List<Map<String, Object>>> resultMap = new HashMap<>();
        for (Trans tree : treeList) {
            if (tree.type() == TransType.TREE) {
                String treeId = tree.id();
                Tree treeConfig = treeService.getById(Long.valueOf(treeId));
                JSONObject configJson = JSON.parseObject(treeConfig.getConfig());
                Integer type = treeConfig.getType();
                if (type == 1) {
                    // 静态数据
                    JSONArray staticData = configJson.getJSONArray("staticData");
                    resultMap.put(treeId, buildTreeToList(staticData, "label", "value", StrUtil.EMPTY));
                } else if (type == 2) {
                    // API数据
                    JSONObject apiData = configJson.getJSONObject("apiData");
                    JSONObject apiConfig = apiData.getJSONObject("apiConfig");
                    String apiId = apiConfig.getString("id");
                    Map<String, Object> data = magicApiService.executeApi(apiId);

                    JSONArray apiColumns = apiData.getJSONArray("apiColumns");
                    String label = ((JSONObject)apiColumns.get(0)).getString("dataIndex");
                    String value = ((JSONObject)apiColumns.get(1)).getString("dataIndex");

                    resultMap.put(treeId, buildTreeToList((JSONArray) JSONArray.toJSON(data.get("data")), label, value, StrUtil.EMPTY));

                }
            }
        }
        return resultMap;
    }

    private List<Map<String, Object>> buildTreeToList(JSONArray list, String label, String value, String parentValue) {
        List<Map<String, Object>> resultList = new ArrayList<>(list.size());
        for (Object obj : list) {
            JSONObject data = (JSONObject) obj;
            Map<String, Object> map = new HashMap<>(2);
            map.put("label", data.getString(label));
            String dataValue = MapUtils.getString(data, value);
            String fullDataValue = StrUtil.isBlank(parentValue) ? dataValue : parentValue + StringPool.DASH + StringPool.DASH + StringPool.DASH + dataValue;
            map.put("value", fullDataValue);
            JSONArray children = data.getJSONArray("children");
            if (CollectionUtils.isNotEmpty(children)) {
                resultList.addAll(buildTreeToList(children, label, value, fullDataValue));
            }
            resultList.add(map);
        }
        return resultList;
    }
}
